/*
 * @Description: 定义 snake 类
 * @notes: 
 * @Author: 本火山
 * @Date: 2024-03-26 17:35:21
 * @LastEditors: 台火山
 * @LastEditTime: 2024-03-27 23:36:04
 */

class Snake {
    // 获取蛇的容器
    element: HTMLElement;
    head: HTMLElement;
    // 蛇的身体(包括蛇头)
    bodies: HTMLCollection;

    constructor() {
        // const snake = document.getElementById('snake');
        this.element = document.getElementById('snake')!;
        this.head = document.querySelector('#snake > div')! as HTMLElement;
        this.bodies = this.element.getElementsByTagName('div')!;
    }

    // 获取蛇头的坐标
    get X() {
        return this.head.offsetLeft;
    }

    get Y() {
        return this.head.offsetTop;
    }
    set X(value: number) {
        // 如果新值和旧值相同则直接返回
        if (this.X === value) {
            return;
        }
        // X 的值合法范围0-290之间
        if (value < 0 || value > 290) {
            // 撞墙
            throw new Error('蛇撞墙了');
        }

        // 修改 X 时，是在修改水平坐标。不能向相反方向掉头
        if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === value) {
            // console.log('水平方向掉头');
            // 如果发生掉头，让蛇反方向继续移动
            if (value > this.X) {
                // 如果新值 value 大于旧值 X，则说明蛇在向右走，此时发生掉头，应该使蛇继续向左走
                value = this.X - 10;
            } else {
                value = this.X + 10;
            }
        }

        // 移动身体
        this.moveBody();

        this.head.style.left = value + 'px';
        
        // 检查有没有撞到自己
        this.checkHeadBody();
    }
    set Y(value: number) {
        // 如果新值和旧值相同则直接返回
        if (this.Y === value) {
            return;
        }
        // Y 的值合法范围0-290之间
        if (value < 0 || value > 290) {
            // 撞墙
            console.log('22');
            throw new Error('蛇撞墙了');
        }

        if (this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === value) {
            // 如果发生掉头，让蛇反方向继续移动
            if (value > this.Y) {
                // 如果新值 value 大于旧值 Y，则说明蛇在向右走，此时发生掉头，应该使蛇继续向左走
                value = this.Y - 10;
            } else {
                value = this.Y + 10;
            }
        }

        // 移动身体
        this.moveBody();

        this.head.style.top = value + 'px';

        // 检查有没有撞到自己
        this.checkHeadBody();
    }

    // 蛇增加身体的方法
    addBody() {
        // 向 element 中添加一个 div
        this.element.insertAdjacentHTML('beforeend', `<div></div>`)
    }

    // 添加蛇身体移动的方法
    moveBody() {
        /**
         *  将后面的身体设置为前边身体的位置
         *      第三节 等于 第二节的位置
        */
        // 遍历获取所有的身体
        for (let i = this.bodies.length - 1; i > 0; i--) {
            // 获取前边身体的位置
            let X = (this.bodies[i - 1] as HTMLElement).offsetLeft;
            let Y = (this.bodies[i - 1] as HTMLElement).offsetTop;

            // 将值设置到当前身体上
            (this.bodies[i] as HTMLElement).style.left = X + 'px';
            (this.bodies[i] as HTMLElement).style.top = Y + 'px';

        }
    }

    // 检查舌头是否撞到身子
    checkHeadBody() {
        // 获取所有的身体，检查其是否和蛇头的坐标发生重叠
        for (let i = 1; i < this.bodies.length; i++) {
            let bd = this.bodies[i] as HTMLElement
            if (this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
                // 进入判断说明舌头撞到了身体，游戏结束
                throw new Error('游戏结束');
            }
        }
    }
}

export default Snake;